package com.alm.handle.proxy.decoder;

import com.alm.handle.common.Consist;
import com.alm.handle.util.ByteUtils;
import com.alm.util.InstructionByteUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.ByteProcessor;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

@Slf4j
public class MyDecoder extends ByteToMessageDecoder {

    // 是否要丢弃换行符
    private final boolean stripDelimiter;

    public MyDecoder(final boolean stripDelimiter) {
        this.stripDelimiter = stripDelimiter;
    }


    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        byte[] in = new byte[byteBuf.readableBytes()];
        for (int i = 0; i < byteBuf.readableBytes(); i++) {
            int index = byteBuf.readerIndex() + i;
            in[i] = byteBuf.getByte(index);
        }
        String inStr = ByteUtils.bytes2String(in);
        log.info("MyDecoder is called,byteBuf.readableBytes {}", byteBuf.readableBytes());
        log.info("ByteBuf to String: {}", inStr);
        // 判断该包是普通数据包还是心跳包，普通包则截取普通包总长度字段()缓进行处理，心跳包长度为2
        int length = 0;
        ByteBuf frame = null;
        if (Arrays.equals(new byte[]{in[0]}, Consist.HEARTBEAT)) {
            // 若为心跳包
            length = 1;
        } else if (Arrays.equals(new byte[]{in[0], in[1], in[2]}, Consist.ALM_PREFIX)) {
            byte[] packLen = new byte[]{in[3], in[4]};
            length = ByteUtils.bytes2Short(packLen, true);
            log.info("Pack length: {}", length);
        }
        if (this.stripDelimiter) {
            // 丢弃分隔符
            frame = byteBuf.readRetainedSlice(length);
            byteBuf.skipBytes(1);
        } else {
            frame = byteBuf.readRetainedSlice(length + 1);
        }
        if (frame != null) {
            list.add(frame);
        }
    }
}


//    private  byte[] head;
//    private final int maxLength;
//    private final boolean stripDelimiter;
//    public MyDecoder(byte[] head, int maxlenth) {
//        this(head,maxlenth,true);
//    }
//
//    public MyDecoder(byte[] head, int maxlenth, boolean stripDelimiter) {
//        this.head = head;
//        this.maxLength = maxlenth;
//        this.stripDelimiter = stripDelimiter;
//    }
//
//    @Override
//    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)  {
//       try {
//           Object decoded = this.decode(ctx, in);
//           if (decoded != null) {
//               out.add(decoded);
//           }
//       }catch (Exception e){
//           e.printStackTrace();
//       }
//
//    }
//    protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer){
//        byte [] dataHead=new byte[this.head.length];
//        for(int i=0;i<head.length;i++){
//            int readindex=buffer.readerIndex()+i;
//            dataHead[i]=buffer.getByte(readindex);
//        }
//        if(checkHead(dataHead)){
//            ByteBuf frame=null;
//            byte[] th= new byte[]{buffer.getByte(dataHead.length),
//                    buffer.getByte(dataHead.length+1)};
//            int  length= InstructionByteUtils.byteArrayToShort(th,0,true);
//            if((length+1)>buffer.readableBytes()){
//                return null;
//            }
//            if (this.stripDelimiter) {
//                frame = buffer.readRetainedSlice(length);
//                buffer.skipBytes(1);
//            } else {
//                frame = buffer.readRetainedSlice(length + 1);
//            }
//            return frame;
//        }else{
//            Object frame= this.decode(ctx,buffer,0);
//            return frame;
//        }
//    }
//
//    private  boolean checkHead(byte[] dataHead){
//        for (int i=0;i<head.length;i++){
//            if(head[i]!=dataHead[i]){
//                return false;
//            }
//        }
//        return true;
//    }
//    private  boolean failFast=true;
//    private boolean discarding;
//    private int discardedBytes;
//    private int offset;
//    private int spiltMinLenth;
//    private int minLenth=3;
//
//    public Object decode(ChannelHandlerContext ctx, ByteBuf buffer,int oldlenth)  {
//        try {
//            boolean minlenthB=true;
//            int eol = this.findEndOfLine(buffer,oldlenth);
//            int length;
//            if(eol<=0&&oldlenth>0){
//                eol=buffer.readerIndex()+oldlenth-1;
//                minlenthB=false;
//            }
//            if (!this.discarding) {
//                if (eol >= 0) {
//                    length = eol - buffer.readerIndex();
//                    if(length>minLenth&&length<spiltMinLenth&&minlenthB){
//                        return this.decode(ctx,buffer,length+1);
//                    }
//                    int delimLength = buffer.getByte(eol) == 13 ? 2 : 1;
//                    if (length > this.maxLength) {
//                        buffer.readerIndex(eol + delimLength);
//                        this.fail(ctx, length);
//                        return null;
//                    } else {
//                        ByteBuf frame;
//                        if (this.stripDelimiter) {
//                            frame = buffer.readRetainedSlice(length);
//                            buffer.skipBytes(delimLength);
//                        } else {
//                            frame = buffer.readRetainedSlice(length + delimLength);
//                        }
//
//                        return frame;
//                    }
//                } else {
//                    length = buffer.readableBytes();
//                    if (length > this.maxLength) {
//                        this.discardedBytes = length;
//                        buffer.readerIndex(buffer.writerIndex());
//                        this.discarding = true;
//                        this.offset = 0;
//                        if (this.failFast) {
//                            this.fail(ctx, "over " + this.discardedBytes);
//                        }
//                    }
//
//                    return null;
//                }
//            } else {
//                if (eol >= 0) {
//                    length = this.discardedBytes + eol - buffer.readerIndex();
//                    length = buffer.getByte(eol) == 13 ? 2 : 1;
//                    buffer.readerIndex(eol + length);
//                    this.discardedBytes = 0;
//                    this.discarding = false;
//                    if (!this.failFast) {
//                        this.fail(ctx, length);
//                    }
//                } else {
//                    this.discardedBytes += buffer.readableBytes();
//                    buffer.readerIndex(buffer.writerIndex());
//                    this.offset = 0;
//                }
//
//                return null;
//            }
//        }catch (Exception e){
//            e.printStackTrace();
//        }
//        return null;
//    }
//
//    private void fail(ChannelHandlerContext ctx, int length) {
//        this.fail(ctx, String.valueOf(length));
//    }
//
//    private void fail(ChannelHandlerContext ctx, String length) {
//        ctx.fireExceptionCaught(new TooLongFrameException("frame length (" + length + ") exceeds the allowed maximum (" + this.maxLength + ')'));
//    }
//
//    private int findEndOfLine(ByteBuf buffer,int start) {
//        int totalLength = buffer.readableBytes();
//        int i = buffer.forEachByte(buffer.readerIndex() + start, totalLength - this.offset, ByteProcessor.FIND_LF);
//        if (i >= 0) {
//            this.offset = 0;
//            if (i > 0 && buffer.getByte(i - 1) == 13) {
//                --i;
//            }
//        } else {
//            this.offset = totalLength;
//        }
//
//        return i;
//    }
//}
